/*
 * Copyleft 2011 Power by colen.
 *
 * Project: booking
 * Date: Jul 2, 2011
 */
package com.ydzc.web.util;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;


/**
 * Date Utils Operations
 *
 * @author colen
 */
public final class DateUtil {
    /**
     * Constructor
     */
    private DateUtil() {
    }

    /**
     * date format: yyyy-MM-dd HH:mm:ss
     */
    public static final String DATE_FORMAT_1 = "yyyy-MM-dd HH:mm:ss";
    /**
     * date format: yyyy
     */
    public static final String DATE_FORMAT_YEAR = "yyyy";
    /**
     * date format: yyyy-MM-dd
     */
    public static final String DATE_FORMAT_F = "yyyy-MM-dd";
    /**
     * date format: yyyyMMdd
     */
    public static final String DATE_FORMAT_FS = "yyyyMMdd";
    /**
     * date format锛� MMdd
     */
    public static final String DATE_FORMAT_3 = "MMdd";
    /**
     * date format: yyyyMM
     */
    public static final String DATE_FORMAT_FYM = "yyyyMM";
    /**
     * date format: yyyyMMddHHmmss
     */
    public static final String DATE_FORMAT_4 = "yyyyMMddHHmmss";
    /**
     * date format: yyyyMMddHHmmss
     */
    public static final String DATE_FORMAT_FULL = "yyyyMMddHHmmssSSS";
    /**
     * date format: yyyy-MM-dd HH:mm
     */
    public static final String DATE_FORMAT_YMDHM = "yyyy-MM-dd HH:mm";
    /**
     * date format: HH:mm
     */
    public static final String DATE_FORMAT_HSF = "HH:mm";
    public static final String DATE_FORMAT_FULL_ZH = "yyyy年MM月dd日 HH时mm分";

    /**
     * 生成标准日期,格式为 YYYY-MM-DD
     *
     * @param date The Date
     * @return 生成日期, 格式为 YYYY-MM-DD
     */
    public static String toDateString(Date date) {
        return toDateString(date, "-");
    }

    /**
     * 生成标准日期,格式为 YYYY+spe+MM+spe+DD
     *
     * @param date The Date
     * @return 生成日期, 格式为 YYYY+spe+MM+spe+DD
     */
    public static String toDateString(Date date, String spe) {
        if (date == null)
            return "";

        Calendar calendar = Calendar.getInstance();

        calendar.setTime(date);
        int month = calendar.get(Calendar.MONTH) + 1;
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        int year = calendar.get(Calendar.YEAR);

        String monthStr = "" + month;
        String dayStr = "" + day;
        String yearStr = "" + year;

        if (month < 10)
            monthStr = "0" + month;

        if (day < 10)
            dayStr = "0" + day;

        return yearStr + spe + monthStr + spe + dayStr;
    }

    /**
     * Change format
     *
     * @param date
     * @param oldFmt
     * @param newFmt
     * @return
     */
    public static String chgFmt(String date, String oldFmt, String newFmt) throws ParseException {
        Date d = toDate(date, oldFmt);
        SimpleDateFormat fmt = new SimpleDateFormat(newFmt);
        return fmt.format(d);
    }

    /**
     * format date
     *
     * @param date
     * @param fmt
     * @return
     */
    public static String format(Date date, String fmt) {
        SimpleDateFormat fmter = new SimpleDateFormat(fmt);
        return fmter.format(date);
    }

    public static Calendar getAddedDateStart(Date d, int addDays) {
        Calendar c = Calendar.getInstance();
        c.setTime(d);

        c.set(c.get(Calendar.YEAR), c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        c.set(Calendar.MILLISECOND, 0);

        c.add(Calendar.DAY_OF_MONTH, addDays);

        return c;
    }

    /**
     * 获取 当前日期的前几天
     *
     * @param amount
     * @param param
     * @return
     */
    public static String beforeDay(int amount, String param) {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -amount);
        String day = new SimpleDateFormat(param).format(cal.getTime());
        return day;
    }

    /**
     * 获取当前日期的后几天
     *
     * @param amount
     * @param param
     * @return
     */
    public static String afterDay(int amount, String param) {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, +amount);
        String day = new SimpleDateFormat(param).format(cal.getTime());
        return day;
    }

    /**
     * 获取指定日期的后几天
     *
     * @param amount
     * @param param
     * @return
     */
    public static String afterDay(int amount, String param, String str) {
        Calendar cal = StringToCalendar(str);
        cal.add(Calendar.DATE, +amount);
        String day = new SimpleDateFormat(param).format(cal.getTime());
        return day;
    }

    /**
     * 获取指定日期的前几天
     *
     * @param amount
     * @param param
     * @return
     */
    public static String beforeDay(int amount, String param, String str) {
        Calendar cal = StringToCalendar(str);
        cal.add(Calendar.DATE, -amount);
        String day = new SimpleDateFormat(param).format(cal.getTime());
        return day;
    }

    /**
     * String 转化Calendar
     *
     * @param str
     * @return
     */
    public static Calendar StringToCalendar(String str) {
        Date date = StringToDate(str, DATE_FORMAT_F);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar;
    }

    /**
     * String 转化Date
     *
     * @param str
     * @return
     */
    public static Date StringToDate(String str, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Date date = null;
        try {
            date = sdf.parse(str);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return date;
    }

    /**
     * Date转String
     *
     * @param date
     * @param format
     * @return
     */
    public static String DateToString(Date date, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        String s = sdf.format(date);
        return s;
    }

    /**
     * Get Date
     *
     * @param format
     * @param offset
     * @return
     */
    public static String getDate(String format, int offset) {
        return getTime(format, Calendar.DATE, offset);
    }

    /**
     * get current date with format
     *
     * @param format format
     * @return
     */
    public static String getDate(String format) {
        return getDate(format, 0);
    }

    /**
     * format date
     *
     * @param date
     * @param format
     * @return
     */
    public static Date toDate(String date, String format) throws ParseException {
        SimpleDateFormat fmt = new SimpleDateFormat(format);
        return fmt.parse(date);
    }

    /**
     * format date
     *
     * @param date
     * @param format
     * @return
     */
    public static Date toDateIngoreException(String date, String format) {
        SimpleDateFormat fmt = new SimpleDateFormat(format);
        try {
            return fmt.parse(date);
        } catch (ParseException e) {
            return new Date();
        }
    }

    public static int getCurrentYear() {
        Calendar cal = Calendar.getInstance();
        return cal.get(Calendar.YEAR);
    }

    public static int getCurrentMonth() {
        Calendar cal = Calendar.getInstance();
        return cal.get(Calendar.MONTH) + 1;
    }

    public static int getDateDayInWeek(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        boolean isFirstSunday = (cal.getFirstDayOfWeek() == Calendar.SUNDAY);
        int weekDay = cal.get(Calendar.DAY_OF_WEEK);
        if (isFirstSunday) {
            weekDay = weekDay - 1;
            if (weekDay == 0) {
                weekDay = 7;
            }
        }

        return weekDay;
    }

    /**
     * Get Time
     *
     * @param format     Format
     * @param offsetType Offset type
     * @param offset     offset.
     * @return String.
     */
    public static String getTime(String format, int offsetType, int offset) {
        SimpleDateFormat fmt = new SimpleDateFormat(format);
        Calendar cal = Calendar.getInstance();
        cal.add(offsetType, offset);
        return fmt.format(cal.getTime());
    }

    public static Date getDate(int offsetType, int offset) {
        Calendar cal = Calendar.getInstance();
        cal.add(offsetType, offset);
        return cal.getTime();
    }

    public static Date getDateS(int offset) {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, offset);
        return cal.getTime();
    }

    /**
     * @param d
     * @param offset
     * @return
     */
    public static Date addDate(Date d, int offset) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);
        cal.add(Calendar.DATE, offset);
        return cal.getTime();
    }

    /**
     * @param d
     * @param offset
     * @return
     */
    public static Date addOffset(Date d, int type, int offset) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);
        cal.add(type, offset);
        return cal.getTime();
    }

    public static Date getDateLastSecond(Date d) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);
        cal.add(Calendar.DATE, 1);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.add(Calendar.SECOND, -1);

        return cal.getTime();
    }

    /**
     * Compare specified time to Current time by the Day offset.
     *
     * @param time      time
     * @param dayoffset day offset
     * @return compare result
     */
    public static boolean compareTime(long time, int dayoffset) {
        Calendar curtime = GregorianCalendar.getInstance(Locale.getDefault());
        curtime.add(Calendar.DAY_OF_MONTH, dayoffset);
        // OUT >>>
        return curtime.getTimeInMillis() >= time ? true : false;
    }

    public static int getLastDateOfMonth(int year, int month) {
        boolean isleap = year % 100 == 0 ? year % 400 == 0 : year % 4 == 0;

        if (month == 2) {
            return isleap ? 29 : 28;
        }

        return month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12 ? 31
                : 30;
    }

    public static boolean isLeapYear(int year) {
        return year % 100 == 0 ? year % 400 == 0 : year % 4 == 0;
    }

    /**
     * Get Current Time
     *
     * @return current time.
     */
    public static Timestamp getCurrentTime() {
        return new Timestamp(Calendar.getInstance(Locale.CHINA).getTimeInMillis());
    }

    /**
     * Get Current Date
     *
     * @return current date
     */
    public static Date getCurrentDate() {
        return Calendar.getInstance(Locale.CHINA).getTime();
    }

    /**
     * Is Date In.
     *
     * @param currentDate Current date.
     * @param startDate   Start date.
     * @param endDate     End date.
     * @return boolean.
     */
    public static boolean isDateIn(String currentDate, String startDate, String endDate) {
        if (currentDate.compareTo(startDate) >= 0 && currentDate.compareTo(endDate) <= 0) {
            return true;
        }
        return false;
    }

    /**
     * 调节时间，添加到eventTime
     *
     * @param licdate
     * @param minOrMax
     * @return
     */
    public static Timestamp toDateFromLic(String licdate, boolean minOrMax) {
        if (minOrMax) {
            licdate = licdate + " 00:00:00:000";
        } else {
            licdate = licdate + " 23:59:59:999";
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
        try {
            return new Timestamp(sdf.parse(licdate).getTime());
        } catch (Exception e) {
            return new Timestamp((new Date()).getTime());
        }
    }

    private static final SimpleDateFormat YMD_SDF = new SimpleDateFormat(DATE_FORMAT_F);
    private static final SimpleDateFormat YMD_HMSDF = new SimpleDateFormat(DATE_FORMAT_YMDHM);
    private static final SimpleDateFormat HM_SDF = new SimpleDateFormat(DATE_FORMAT_HSF);

    public static class DataHolder {
        private static List<String> holidayList = new ArrayList<String>();
        ;
        private static String WORK_START = "08:30";
        private static String WORK_END = "17:30";
    }

    /**
     * 计算某一天经过某时间段后的日期
     *
     * @param fromDate
     * @param during
     * @param workdayOnly
     * @return
     */
    public static Date calcEndDate(Date fromDate, int during, boolean workdayOnly) {
        List<String> hoildays = DataHolder.holidayList;
        if (!workdayOnly) {
            return addDate(fromDate, during);
        }

        // 开始时间在休息日，则延长到下个工作日
        String fromYMDDate = YMD_SDF.format(fromDate);
        String fromHMDate = HM_SDF.format(fromDate);
        boolean frontFlg = false;
        while (hoildays.contains(fromYMDDate)) {
            fromDate = addDate(fromDate, 1);
            fromYMDDate = YMD_SDF.format(fromDate);
            frontFlg = true;
        }
        try {
            if (frontFlg) {
                fromDate = YMD_HMSDF.parse(fromYMDDate + " " + DataHolder.WORK_START);
            } else {
                if (fromHMDate.compareTo(DataHolder.WORK_START) < 0) {
                    fromDate = YMD_HMSDF.parse(fromYMDDate + " " + DataHolder.WORK_START);
                } else if (fromHMDate.compareTo(DataHolder.WORK_END) > 0) {
                    fromDate = YMD_HMSDF.parse(fromYMDDate + " " + DataHolder.WORK_END);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

        // 开始计算工作日
        int leftDuring = during;
        Date endDate = fromDate;
        while (leftDuring > 0) {
            endDate = addDate(endDate, 1);
            if (!hoildays.contains(YMD_SDF.format(endDate))) {
                leftDuring--;
            }
        }

        return endDate;
    }

    /**
     * 单位 小时
     *
     * @param fromDate
     * @param toDate
     * @return
     */
    public static float calcWorkDays(Date fromDate, Date toDate) {
        List<String> hoildays = DataHolder.holidayList;

        if (fromDate.compareTo(toDate) > 0) {
            return -calcWorkDays(toDate, fromDate);
        }

        String fromYMDDate = YMD_SDF.format(fromDate);
        String toYMDDate = YMD_SDF.format(toDate);
        String fromHMDate = HM_SDF.format(fromDate);
        String toHMDate = HM_SDF.format(toDate);
        boolean frontFlg = false;
        boolean afterFlg = false;

        while (hoildays.contains(fromYMDDate)) {
            fromDate = addDate(fromDate, 1);
            fromYMDDate = YMD_SDF.format(fromDate);
            frontFlg = true;
        }
        while (hoildays.contains(toYMDDate)) {
            toDate = addDate(toDate, 1);
            toYMDDate = YMD_SDF.format(toDate);
            afterFlg = true;
        }

        try {
            if (frontFlg) {
                fromDate = YMD_HMSDF.parse(fromYMDDate + " " + DataHolder.WORK_START);
            } else {
                if (fromHMDate.compareTo(DataHolder.WORK_START) < 0) {
                    fromDate = YMD_HMSDF.parse(fromYMDDate + " " + DataHolder.WORK_START);
                } else if (fromHMDate.compareTo(DataHolder.WORK_END) > 0) {
                    fromDate = YMD_HMSDF.parse(fromYMDDate + " " + DataHolder.WORK_END);
                }
            }
            if (afterFlg) {
                toDate = YMD_HMSDF.parse(toYMDDate + " " + DataHolder.WORK_START);
            } else {
                if (toHMDate.compareTo(DataHolder.WORK_START) < 0) {
                    toDate = YMD_HMSDF.parse(toYMDDate + " " + DataHolder.WORK_START);
                } else if (toHMDate.compareTo(DataHolder.WORK_END) > 0) {
                    toDate = YMD_HMSDF.parse(toYMDDate + " " + DataHolder.WORK_END);
                }
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }

        int subCnt = 0;
        for (String ho : hoildays) {
            if (ho.compareTo(fromYMDDate) < 0) {
                continue;
            } else if (ho.compareTo(toYMDDate) > 0) {
                break;
            } else {
                subCnt++;
            }
        }

        long millsec = toDate.getTime() - fromDate.getTime() - subCnt * 24 * 3600000;

        int hours = (int) (millsec / 3600000);
        int days = hours / 24;

        int leftHours = hours - days * 24;
        if (leftHours >= 15) {
            leftHours -= 15;
        }
        return days + (leftHours / 9.0f);
    }

    public static Date getYearFirstDay() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DATE, 1);
        calendar.set(Calendar.MONTH, 0);

        return calendar.getTime();
    }

    /**
     * 以乐观方式去解锁一个日期值
     *
     * @param dateStr
     * @return
     */
    public static Date toIngoreDate(String dateStr) {
        String[] str = dateStr.split("-|/|:|(\\s)+|　");

        int[] arr = new int[]{2000, 1, 1, 0, 0, 0, 0};

        for (int i = 0; i < str.length; i++) {
            if (i > 6) {
                break;
            }
            String s = str[i];
            try {
                arr[i] = Integer.parseInt(s);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        StringBuffer tmBuf = new StringBuffer();
        for (int t : arr) {
            if (tmBuf.length() != 0) {
                tmBuf.append("-");
            }
            tmBuf.append(t);
        }

        SimpleDateFormat fmt = new SimpleDateFormat("y-M-d-H-m-s-S");
        try {
            return fmt.parse(tmBuf.toString());
        } catch (Exception e) {
            e.printStackTrace();
            return new Date();
        }
    }

    /**
     * String ->Timestamp 注：String的类型必须形如： yyyy-mm-dd hh:mm:ss[.f...]
     * 这样的格式，中括号表示可选，否则报错！！！
     *
     * @param date
     * @return
     */
    public static Timestamp stringToTimestamp(String date) {
        Timestamp ts = new Timestamp(System.currentTimeMillis());
        ts = Timestamp.valueOf(date);
        return ts;
    }

    /**
     * Timestamp -> String
     *
     * @param date
     * @return
     */
    public static String timestampToString(Timestamp date) {
        Timestamp ts = new Timestamp(System.currentTimeMillis());
        DateFormat sdf = new SimpleDateFormat(DATE_FORMAT_1);
        return sdf.format(ts);
    }

    public static String getYear() {
        Timestamp ts = new Timestamp(System.currentTimeMillis());
        DateFormat sdf = new SimpleDateFormat(DATE_FORMAT_YEAR);
        return sdf.format(ts);
    }

    public static String getTime(String user_time, String format) {
        String re_time = null;
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Date d;
        try {
            d = sdf.parse(user_time);
            long l = d.getTime();
            String str = String.valueOf(l);
            re_time = str.substring(0, 10);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return re_time;
    }

    public static Timestamp timeStampStrToTimeStamp(String timeStr) {
        long time = Long.valueOf(timeStr) / 1000L;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date = sdf.format(new Date(time * 1000L));
        return stringToTimestamp(date);
    }

    public static String NaNtoEmpty(String time) {
        if ("NaN".equals(time)) {
            return "";
        }
        return time;
    }
}
